//-------------------------------------------------------------------------------------
// <copyright file="ReceivePort.cs" company="Microsoft">
//      Copyright (c) 2003 Microsoft Corporation. All rights reserved.
//      THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
//      EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
//      WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
// </copyright>
// <summary>
//      Represents the logical port through which partners interact with the business process for sending messages.
// </summary>  
//-------------------------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.BizTalk2004.Configuration
{
	#region Using Directives
    
	using System;
	using System.Collections;
    using System.Xml.Serialization;

	
	#endregion 

    /// <summary>
    /// Represents the logical port through which partners interact with the business process for sending messages.
    /// </summary>
    internal class ReceivePort : BizTalkConfigurableEntityBase 
    {
		#region Member Variables 
        private bool twoWay;
        private Pipeline sendPipeline;
		private string customData;
        private AuthenticationType authenticationType;
        private TrackingTypes trackingType;
		private MapCollection inboundTransforms = new MapCollection();
		private MapCollection outboundTransforms = new MapCollection();

		private ReceiveLocationCollection receiveLocations;

		#endregion 
		
		#region Methods 

		/// <summary>
		/// Creates a new ReceivePort instance. Used by external applications.
		/// </summary>
		/// <param name="installation">The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> of this receive port.</param>
		///<param name="name">The name of this receive port.</param>
		///<param name="twoWay">true if the receive port is two-way; otherwise, false</param>
		public ReceivePort(BizTalkInstallation installation, string  name, bool twoWay) : base(installation)
		{
			this.Name = name;
			this.twoWay = twoWay;

		}

	
		/// <summary>
		/// Creates a new ReceivePort instance. This is private because instance of this class can only be created with
		/// the Load method
		/// </summary>
		/// <param name="installation">The <see cref="Microsoft.Sdc.Tasks.BizTalk2004.Configuration.BizTalkInstallation"/> of this receive port.</param>
		///<param name="name">The name of this receive port.</param>
		private ReceivePort(BizTalkInstallation installation, string name) : base(installation, name)
		{
			this.Loaded = true;

		}



		/// <summary>
		/// Loads a new Receive Port
		/// </summary>
		/// <param name="installation">The BizTalk installation to load the Receive Port from</param>
		/// <param name="name">Name of the Receive Port to Load</param>
		/// <returns>the loaded Receive Port</returns>
		public static ReceivePort Load(BizTalkInstallation installation, string name)
		{
			//check inputs
			if (installation == null) throw new ArgumentException("installation");
			if (name == null || name.Length == 0) throw new ArgumentException("name");

	
			ReceivePort receivePort = null;
			BtsReceivePort rxPort = installation.CatalogExplorer.ReceivePorts[name];

			if (rxPort != null)
			{
				receivePort = new ReceivePort(installation, rxPort.Name);
				receivePort.twoWay = rxPort.IsTwoWay;
				receivePort.authenticationType = (AuthenticationType)Enum.Parse(typeof(AuthenticationType), ((int)rxPort.Authentication).ToString());
				receivePort.customData = rxPort.CustomData;
				receivePort.trackingType = (TrackingTypes)Enum.Parse(typeof(TrackingTypes), ((int)rxPort.Tracking).ToString());

				//inbound maps
				if (rxPort.InboundTransforms != null)
				{
					foreach(object transform in rxPort.InboundTransforms)
					{
						BtsTransform actualTransform = new BtsTransform(transform , rxPort.BtsCatalogExplorer);
						receivePort.inboundTransforms.Add(Map.Load(installation.DeployedAssemblies[actualTransform.BtsAssembly.DisplayName], actualTransform.FullName));
					}
				}

				if (receivePort.twoWay)
				{
					BizTalkAssembly _assembly = BizTalkAssembly.Load(installation, rxPort.SendPipeline.BtsAssembly.DisplayName);
					receivePort.sendPipeline = Pipeline.Load(_assembly, rxPort.SendPipeline.FullName);

					//outbound maps
					if (rxPort.OutboundTransforms != null)
						foreach(object transform in rxPort.OutboundTransforms)
						{
							BtsTransform actualTransform = new BtsTransform(transform , rxPort.BtsCatalogExplorer);
							receivePort.outboundTransforms.Add(Map.Load(installation.DeployedAssemblies[actualTransform.BtsAssembly.DisplayName], actualTransform.FullName));
						}
				}

			}
			return receivePort;
		}
        

		public static void Delete(BizTalkInstallation installation,  string name)
		{
			BtsReceivePort rxPort = installation.CatalogExplorer.ReceivePorts[name];

			if (rxPort != null)
			{
				//removing the receive Port
				installation.CatalogExplorer.RemoveReceivePort(rxPort);
				installation.CatalogExplorer.SaveChanges();

			}
		}

		/// <summary>
		/// Deletes the current object. 
		/// </summary>
		public void Delete()
		{
			Delete(this.Installation, this.Name);
		}
	
		/// <summary>
		/// Overriden. Saves the object. This method is called by Save() from the base class 
		/// </summary>
		protected internal override void SaveImpl()
		{
			try
			{
				//if in create mode and rxPort already exists.
				if (!this.Loaded && ReceivePort.Exists(this.Installation, this.Name))
					throw new InvalidOperationException(string.Format("ReceivePort '{0}' already exists. Specify a unique ReceivePort name.", this.Name));

				BtsReceivePort rxPort = this.Installation.CatalogExplorer.ReceivePorts[this.Name];

				// create if it doesnt already exists.
				if (rxPort == null)
					rxPort = this.Installation.CatalogExplorer.AddNewReceivePort(this.twoWay);

				rxPort.Name = this.Name; 
				rxPort.Authentication = (AuthenticationType)Enum.Parse(typeof(AuthenticationType), ((int)this.authenticationType).ToString());
				rxPort.CustomData = this.customData;


				if (((int) this.trackingType) != 0)
					rxPort.Tracking = (TrackingTypes)Enum.Parse(typeof(TrackingTypes),((int)this.trackingType).ToString());

				if (this.InboundTransforms.Count > 0)
				{
					rxPort.InboundTransforms.Clear();
					foreach(Map map in this.inboundTransforms)
						rxPort.InboundTransforms.Add(this.Installation.CatalogExplorer.Transforms[map.Name, map.Assembly.Name].actualBtsObject);
				}
				else
				{
					rxPort.InboundTransforms.Clear();
				}


				if (this.twoWay)
				{
					rxPort.SendPipeline = this.Installation.CatalogExplorer.Pipelines[this.sendPipeline.Name];

					if (this.OutboundTransforms.Count > 0)
					{
						rxPort.OutboundTransforms.Clear();
						foreach(Map map in this.outboundTransforms)
							rxPort.OutboundTransforms.Add(this.Installation.CatalogExplorer.Transforms[map.Name, map.Assembly.Name].actualBtsObject);
					}
					else
					{
						rxPort.OutboundTransforms.Clear();
					}
				}
			}
			catch
			{
				this.Installation.CatalogExplorer.DiscardChanges();
				throw;
			}
		}

		/// <summary>
		/// Checks if the Receive Port exists within BizTalk
		/// </summary>
		/// <param name="installation">
		/// The Microsoft.Sdc.Tasks.Configuration.BizTalk.Installation to search in.
		/// </param>
		/// <param name="name">
		/// The name of the Receive Port
		/// </param>
		/// <returns>
		/// <b>true</b> if the Receive Port exists, or <b>false</b> otherwise.
		/// </returns>
		public static bool Exists(BizTalkInstallation installation, string name)
		{
			return BizTalkEntityBase.Exists(installation, CollectionType.ReceivePort, name);
		}

		/// <summary>
		/// Adds a new receive location to this receive port.
		/// </summary>
		/// <param name="receiveLocation"></param>
		public void AddNewReceiveLocation (ReceiveLocation receiveLocation)
		{
			BtsReceivePort rxPort = this.Installation.CatalogExplorer.ReceivePorts[this.Name];
			BtsReceiveLocation rxLocation  = rxPort.AddNewReceiveLocation();

            rxLocation.Name = receiveLocation.Name;
			rxLocation.Address = receiveLocation.Address;
			rxLocation.PublicAddress = receiveLocation.PublicAddress;
			rxLocation.Enable = receiveLocation.Enable;
			foreach (BtsReceiveHandler rxHandler in this.Installation.CatalogExplorer.ReceiveHandlers)
			{
				if (rxHandler.Host.Name == receiveLocation.ReceiveHandler.Host.Name && rxHandler.TransportType.Name == receiveLocation.TransportType.Name)
				{
					rxLocation.ReceiveHandler = rxHandler;
					break;
				}
			}
			rxLocation.ReceivePipeline = this.Installation.CatalogExplorer.Pipelines[receiveLocation.ReceivePipeline.Name];

			rxLocation.StartDateEnabled = receiveLocation.StartDateEnabled;
			rxLocation.StartDate = receiveLocation.StartDate;
			rxLocation.EndDateEnabled = receiveLocation.EndDateEnabled;
			rxLocation.EndDate = receiveLocation.EndDate;
			rxLocation.TransportType = this.Installation.CatalogExplorer.ProtocolTypes[receiveLocation.TransportType.Name];
			rxLocation.TransportTypeData = receiveLocation.TransportTypeData.GetTransportXml();
			rxLocation.ServiceWindowEnabled = receiveLocation.ServiceWindow.Enabled;
			rxLocation.FromTime = receiveLocation.ServiceWindow.StartTime;
			rxLocation.ToTime = receiveLocation.ServiceWindow.EndTime;

			this.Installation.CatalogExplorer.SaveChanges();
		}

		/// <summary>
		/// Removes the specified receive location from this receive port.
		/// </summary>
		/// <param name="receiveLocation"></param>
		public void RemoveReceiveLocation (ReceiveLocation receiveLocation)
		{
			ReceiveLocation.Delete(this, receiveLocation.Name);
		}
		
		#endregion 

		#region Properties

		/// <summary>
		/// Gets or sets an enumeration value to specify whether authentication is needed at this receive port. 
		/// </summary>
		public AuthenticationType AuthenticationType
		{
			get { return this.authenticationType; }
			set { this.authenticationType = value; }
		}

		/// <summary>
		/// Gets or sets the custom data with the receive port.
		/// </summary>
		public string CustomData
		{
			get {return this.customData; }
			set {this.customData = value;}
		}

		/// <summary>
		/// Gets the collection of maps to apply to inbound documents.
		/// </summary>
		public MapCollection InboundTransforms
		{
			get
			{
				return this.inboundTransforms;
			}
		}

		/// <summary>
		/// Determines whether the receive port is a two-way port.
		/// </summary>
		public bool TwoWay
		{
			get { return this.twoWay; }
			set { this.twoWay = value; }
		}

		/// <summary>
		/// Gets the collection of maps to apply to outbound documents on the two-way receive port.
		/// </summary>
		public MapCollection OutboundTransforms
		{
			get { return this.outboundTransforms ;}
		}

		/// <summary>
		/// Gets the primary receive location for this receive port.
		/// </summary>
		public ReceiveLocation PrimaryReceiveLocation
		{
			get 
			{
				ReceiveLocation _receiveLocation = null;
				foreach(ReceiveLocation recvLocation in this.ReceiveLocations)
				{
					if (recvLocation.IsPrimary)
					{
						_receiveLocation = recvLocation;
						break;
					}

				}
				return _receiveLocation;
			}
		}

		/// <summary>
		/// Gets the collection of receive locations that make up this receive port.
		/// </summary>
		[XmlArrayItem("ReceiveLocation", typeof(ReceiveLocation))]
		public ReceiveLocationCollection ReceiveLocations
		{
			get
			{
				if (this.receiveLocations == null)
				{
					this.receiveLocations = new ReceiveLocationCollection();
					BtsReceivePort actualPort = this.Installation.CatalogExplorer.ReceivePorts[this.Name];
					if (actualPort != null)
					{
						foreach (BtsReceiveLocation rxLocation in actualPort.ReceiveLocations)
						{
							ReceiveLocation receiveLocation = ReceiveLocation.Load(this, rxLocation.Name);
							receiveLocation.Address = rxLocation.Address;
							receiveLocation.Name = rxLocation.Name;
							receiveLocation.ReceiveHandler = ReceiveHandler.Load(this.Installation, rxLocation.ReceiveHandler.Name, rxLocation.ReceiveHandler.TransportType.Name);
							receiveLocation.ReceivePipeline = Pipeline.Load(this.Installation.DeployedAssemblies[rxLocation.ReceivePipeline.BtsAssembly.DisplayName],  rxLocation.ReceivePipeline.FullName );
							receiveLocation.TransportType = Protocol.Load(this.Installation, rxLocation.TransportType.Name);
							this.receiveLocations.Add(receiveLocation);
						}
					}
				}
				return this.receiveLocations; 
			}
		}

		/// <summary>
		/// Gets or sets the send pipeline used to send a response if this is a two way receive port.
		/// </summary>
		public Pipeline SendPipeline
		{
			get { return this.sendPipeline; }
			set { this.sendPipeline = (this.twoWay)?value:null;}
		}
		
		/// <summary>
		/// Gets or sets the tracking needed for this port.
		///
		/// </summary>
		public TrackingTypes TrackingType
		{
			get { return this.trackingType; }
			set { this.trackingType = value; }
		}


		#endregion 		
    }
}

